package org.loofer.ext.utils;

import java.util.LinkedList;

public abstract class Pool<T> {
    private final int mCapacity;

    public static class SimplePool<T> extends Pool<T> {
        private final LinkedList<T> mList = new LinkedList();

        public SimplePool(int capacity) {
            super(capacity);
        }

        public void put(T item) {
            if (item != null) {
                int capacity = capacity();
                if (capacity <= 0 || size() < capacity) {
                    this.mList.offer(item);
                }
            }
        }

        public T get() {
            return size() <= 0 ? create() : this.mList.poll();
        }

        private int size() {
            return this.mList.size();
        }
    }

    public static class SynchronizedPool<T> extends SimplePool<T> {
        private final Object mLock = new Object();

        public SynchronizedPool(int capacity) {
            super(capacity);
        }

        public void put(T item) {
            synchronized (this.mLock) {
                super.put(item);
            }
        }

        public T get() {
            T t;
            synchronized (this.mLock) {
                t = super.get();
            }
            return t;
        }
    }

    public static class ThreadLocalPool<T> extends Pool<T> {
        private final ThreadLocal<LinkedList<T>> mThreadLocalList = new ThreadLocal<LinkedList<T>>() {
            protected LinkedList<T> initialValue() {
                return new LinkedList();
            }
        };

        public ThreadLocalPool(int capacity) {
            super(capacity);
        }

        public void put(T item) {
            if (item != null) {
                LinkedList<T> list = (LinkedList) this.mThreadLocalList.get();
                int capacity = capacity();
                if (capacity <= 0 || list.size() < capacity) {
                    list.offer(item);
                }
            }
        }

        public T get() {
            LinkedList<T> array = (LinkedList) this.mThreadLocalList.get();
            return array.size() <= 0 ? create() : array.poll();
        }
    }

    public abstract T get();

    public abstract void put(T t);

    public Pool(int capacity) {
        this.mCapacity = capacity;
    }

    public final int capacity() {
        return this.mCapacity;
    }

    protected T create() {
        return null;
    }

    public static <T> Pool<T> simplePool(int capacity) {
        return new SimplePool(capacity);
    }

    public static <T> Pool<T> synchronizedPool(int capacity) {
        return new SynchronizedPool(capacity);
    }

    public static <T> Pool<T> threadLocalPool(int capacity) {
        return new ThreadLocalPool(capacity);
    }
}
